import 'dart:math';
import 'package:flutter/material.dart';

class LYUpvoteGesture extends StatefulWidget {
  final Function()? onTap;
  final Widget child;
  const LYUpvoteGesture({super.key, required this.child, this.onTap});

  @override
  State<LYUpvoteGesture> createState() => _LYUpvoteGestureState();
}

class _LYUpvoteGestureState extends State<LYUpvoteGesture> {
  List<Offset> icons = [];

  bool canAddFavorite = false;
  bool justAddFavorite = false;

  @override
  Widget build(BuildContext context) {
    var iconStack = Stack(
      children: icons
          .map<Widget>(
            (p) => LYUpvoteIcon(
              position: p,
              onAnimationComplete: () {
                icons.remove(p);
              },
            ),
          )
          .toList(),
    );
    return GestureDetector(
      onDoubleTapDown: (detail) {
        setState(() {
          icons.add(detail.localPosition);
        });
      },
      onTap: widget.onTap,
      onTapCancel: () {
        // print('onTapCancel');
      },
      child: Stack(
        children: <Widget>[
          widget.child,
          iconStack,
        ],
      ),
    );
  }
}

class LYUpvoteIcon extends StatefulWidget {
  final Offset position;
  final double size;
  final Function()? onAnimationComplete;
  const LYUpvoteIcon(
      {super.key,
      required this.position,
      this.size = 100,
      this.onAnimationComplete});

  @override
  State<LYUpvoteIcon> createState() => _LYUpvoteIconState();
}

class _LYUpvoteIconState extends State<LYUpvoteIcon>
    with TickerProviderStateMixin {
  AnimationController? _animationController;
  @override
  void dispose() {
    _animationController?.dispose();
    super.dispose();
  }

  @override
  void initState() {
    _animationController = AnimationController(
      lowerBound: 0,
      upperBound: 1,
      duration: const Duration(milliseconds: 600),
      vsync: this,
    );

    _animationController?.addListener(() {
      setState(() {});
    });
    startAnimation();
    super.initState();
  }

  startAnimation() async {
    await _animationController?.forward();
    widget.onAnimationComplete?.call();
  }

  double rotate = pi / 10.0 * (3 * Random().nextDouble() - 2);

  double get value => _animationController?.value ?? 0;

  double appearDuration = 0.2;
  double dismissDuration = 0.5;

  Offset get moveOffset {
    if (value < 0.3) {
      return Offset.zero;
    }
    if (value < 0.6) {
      return Offset(0, -value * 100);
    }
    return Offset(0, -value * 200);
  }

  double get opa {
    if (value < appearDuration) {
      return 0.99 / appearDuration * value;
    }
    if (value < dismissDuration) {
      return 0.99;
    }
    var res = 0.99 - (value - 0.3) / (1 - 0.3);
    return res < 0 ? 0 : res;
  }

  double get scale {
    if (value < appearDuration) {
      return 2 + value;
    }
    if (value < dismissDuration) {
      return 2 - value;
    }
    return (value - dismissDuration) / (1 - dismissDuration) + 2;
  }

  @override
  Widget build(BuildContext context) {
    Widget content = ShaderMask(
      blendMode: BlendMode.srcATop,
      shaderCallback: (Rect bounds) => RadialGradient(
        center: Alignment.topLeft.add(const Alignment(0.66, 0.66)),
        colors: const [
          Color(0xffEF6F6F),
          Color(0xffF03E3E),
        ],
      ).createShader(bounds),
      child: Icon(
        Icons.favorite_sharp,
        size: widget.size,
        color: Colors.redAccent,
      ),
    );
    Widget body = Transform.rotate(
      angle: rotate,
      child: Opacity(
        opacity: opa,
        child: Transform.translate(
          offset: moveOffset,
          child: Transform.scale(
            alignment: Alignment.bottomCenter,
            scale: scale,
            child: content,
          ),
        ),
      ),
    );
    return Positioned(
      left: widget.position.dx - widget.size / 2,
      top: widget.position.dy - widget.size / 2,
      child: body,
    );
  }
}
